package com.cictec.middleware.gps.engine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cictec.middleware.commons.utils.Constants;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.core.entity.Bus;
import com.cictec.middleware.core.entity.Device;
import com.cictec.middleware.gps.service.BusService;
import com.cictec.middleware.gps.service.DeviceService;
import com.cictec.middleware.gps.service.WarnMsgService;

@Component
public class BusInstanceEngine {

	private static Logger logger = LoggerFactory.getLogger(BusInstanceEngine.class);

	@Autowired
	private BusService busService;
	@Autowired
	private DeviceService deviceService;
	@Autowired
	private WarnMsgService warnMsgService;
	@Autowired
	private TimeEventBus timeEventBus;

	private ConcurrentMap<String, BusInstance> devIndexBuses = new ConcurrentHashMap<String, BusInstance>();
	private ConcurrentMap<String, BusInstance> busIndexBuses = new ConcurrentHashMap<String, BusInstance>();

	@PostConstruct
	private void init() {
	}

	/**
	 * 根据设备编号查找busInstance。
	 * 
	 * @param devCode
	 * @return
	 * @throws DeviceCodeUnregistered
	 */
	public BusInstance getBusInstanceByDevCode(String devCode) {
		if (devCode == null) {
			return null;
		}

		BusInstance bi = null;

		// 先在缓存中查找
		bi = devIndexBuses.get(devCode);

		if (bi == null) {
			// 缓存中没有RtBus，去数据库中查找，并放入缓存。
			logger.debug("缓存中没有找到 dev code {}", devCode);
			Bus bus = busService.selectBusByDevCode(devCode);

			if (bus != null) {
				return initBusInstance(bus);
			} else {
				logger.error("【BusInstanceEngine】未找到设备 {} 对应的车辆", devCode);
			}
		} else {
			logger.debug("缓存中找到 dev code {}", devCode);
		}

		return bi;
	}

	/**
	 * 根据车辆的UUID查找busInstance。
	 * 
	 * @param busUuid
	 * @return
	 */
	public BusInstance getBusInstanceByBusUuid(String busUuid) {
		if (busUuid == null) {
			return null;
		}

		BusInstance bi = null;

		// 先在缓存中查找
		bi = busIndexBuses.get(busUuid);

		if (bi == null) {
			logger.debug("缓存中没有找到 busUuid {}", busUuid);
			// 缓存中没有RtBus，去数据库中查找，并放入缓存。
			Bus bus = busService.selectBusByUuid(busUuid);
			if (bus != null) {
				return initBusInstance(bus);
			} else {
				logger.error("【BusInstanceEngine】未找到 busUuid:{} 对应的车辆", busUuid);
			}
		} else {
			logger.debug("缓存中找到 busUuid {}", busUuid);
		}

		return bi;
	}

	private BusInstance initBusInstance(Bus bus) {
		Device device = deviceService.selectDeviceByDevUuid(bus.getBusDevUuid());
		if (device == null) {
			logger.error("【BusInstanceEngine】未找到车辆 {} 对应的设备 {} ", bus.getBusPlateNumber(), bus.getBusDevUuid());
			return null;
		}

		BusInstance busInstance = new BusInstance(bus, device);

		// 加载车辆报警信息，从数据库中
		loadWarnProperties(busInstance);
		// loadParkProperties(busInstance);

		devIndexBuses.putIfAbsent(device.getDevCode(), busInstance);
		busIndexBuses.putIfAbsent(bus.getBusUuid(), busInstance);
		return busInstance;
	}

	public synchronized void setBusInstance(BusInstance busInstance){
		devIndexBuses.putIfAbsent(busInstance.getDevice().getDevCode(), busInstance);
		busIndexBuses.putIfAbsent(busInstance.getBus().getBusUuid(), busInstance);
	}
	
	/**
	 * 获取BusInstanceEngine管理的所有 BusInstance实例
	 * 
	 * @param isOnline
	 *            true:返回所有在线车辆，false:所有在线，非在线的实例对象
	 * @return
	 */
	public List<BusInstance> getAllBusInstance(boolean isOnline) {

		List<BusInstance> busList = new ArrayList<BusInstance>();
		for (String busUuid : busIndexBuses.keySet()) {

			BusInstance busInstance = busIndexBuses.get(busUuid);
			if (busInstance == null) {
				continue;
			}
			// 获取指定线路下的车辆信息
			if (isOnline) {
				if (busIndexBuses.get(busUuid).isDevOnline()) {
					busList.add(busIndexBuses.get(busUuid));
				}
			} else {
				busList.add(busIndexBuses.get(busUuid));
			}
		}
		return busList;
	}

	/**
	 * 【获取指定线路上的车】【在线】
	 * 
	 * @param lineUuid
	 * @return
	 */
	public List<BusInstance> getBusInstanceByLine(String lineUuid) {
		List<BusInstance> busList = new ArrayList<BusInstance>();
		for (String busUuid : busIndexBuses.keySet()) {

			BusInstance busInstance = busIndexBuses.get(busUuid);
			if (busInstance == null) {
				continue;
			}
			if (busInstance.isDevOnline() && lineUuid.equals(PMSUtils.isNull(busInstance.getLineUuid()))) {
				// 获取指定线路下的车辆信息
				if (busIndexBuses.get(busUuid).isDevOnline()) {
					busList.add(busIndexBuses.get(busUuid));
				}
			}
		}
		return busList;
	}

	/**
	 * 【获取指定线路上的车】【在线】【按照相对距离已经排序 ASC, 没有相对距离的排在末尾】
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param sortAble
	 *            true 排序
	 * @return
	 */
	public List<BusInstance> getBusInstanceByLine(String lineUuid, String lineType, boolean sortAble) {

		List<BusInstance> busList = getBusInstanceByLine(lineUuid);
		List<BusInstance> rtList = new ArrayList<BusInstance>();
		for (BusInstance busInstance : busList) {

			if (lineType.equals(busInstance.getLineType())) {
				rtList.add(busIndexBuses.get(busInstance));
			}
		}

		if (sortAble) {
			Collections.sort(rtList, new Comparator<BusInstance>() {
				@Override
				public int compare(BusInstance rb1, BusInstance rb2) {
					String rate1 = rb1.getPositionRate();
					rate1 = PMSUtils.isEmpty(rate1) ? "9999" : rate1;
					String rate2 = rb2.getPositionRate();
					rate2 = PMSUtils.isEmpty(rate2) ? "9999" : rate2;

					Double double1 = Double.parseDouble(rate1) * 10000;
					Double double2 = Double.parseDouble(rate2) * 10000;

					return double1.intValue() - double2.intValue();

				}

			});
		}
		return rtList;
	}

	/**
	 * 获取线路上的实时车辆【在线、相对距离  0<=rate<=1】
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public List<BusInstance> getInLineBus(String lineUuid,String lineType){
		List<BusInstance> busList = getBusInstanceByLine(lineUuid, lineType);
		List<BusInstance> list = new ArrayList<BusInstance>();
		
		for (BusInstance busInstance : busList) {
			if(PMSUtils.isNull(lineUuid).equals(PMSUtils.isNull(busInstance.getLineUuid()))
					&& PMSUtils.isNull(lineType).equals(PMSUtils.isNull(busInstance.getLineType()))
					&& busInstance.isDevOnline()
					&& Constants.VAL_LOGIN_ONLINE.equals(PMSUtils.isNull(busInstance.getLoginStatus()))
					&& busInstance.isInOperateTime()
					&& !PMSUtils.isEmpty(PMSUtils.isNull(busInstance.getPositionRate()))
					){
				list.add(busInstance);
			}
		}
		
		
		Collections.sort(list, new Comparator<BusInstance>(){
			@Override
			public int compare(BusInstance rb1, BusInstance rb2) {
				String rate1 = rb1.getPositionRate();
				String rate2 = rb2.getPositionRate();
				
				Double double1 = Double.parseDouble(rate1) * 10000;
				Double double2 = Double.parseDouble(rate2) * 10000;
				
				return double1.intValue() - double2.intValue();
				
			}
			
		});
		
		return list;
	}
	
	/**
	 * 【获取指定线路上的车】【在线】
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public List<BusInstance> getBusInstanceByLine(String lineUuid, String lineType) {
		return getBusInstanceByLine(lineUuid, lineType, false);
	}

	/**
	 * 【获取指定线路上的车】【在线】【按照相对距离已经排序 ASC】
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public List<BusInstance> getSortBusInstanceByLine(String lineUuid, String lineType) {
		return getBusInstanceByLine(lineUuid, lineType, true);
	}

	/**
	 * 获取所有在线车辆，在线路上跑的车车辆   0< rate && rate < 1 有进站数据的
	 * @return
	 */
	public Map<String, List<BusInstance>> getBusInline(){
		List<BusInstance> busList = getAllBusInstance(true);
		Map<String, List<BusInstance>> map = new ConcurrentHashMap<String, List<BusInstance>>();
		
		for (BusInstance busInstance : busList) {
			
			String rate = PMSUtils.isNull(busInstance.getPositionRate());
			String stationSeq = busInstance.getStationSeq();
			if(busInstance.isInDeviate() 
					|| busInstance.isInStandBy()
					|| PMSUtils.isEmpty(stationSeq) 
					|| PMSUtils.isEmpty(rate) || rate.equals("0") || rate.equals("1") ){
				continue;
			}
			
			String lineUuidType = busInstance.getLineUuid() + "-" + busInstance.getLineType();
			if(!map.containsKey(lineUuidType)){
				List<BusInstance> list = new ArrayList<BusInstance>();
				list.add(busInstance);
				map.put(lineUuidType, list);
			}else{
				map.get(lineUuidType).add(busInstance);
			}
		}
		
		return map;
	}
	

	/**
	 * 设备在线（登录）
	 * @param devOnline
	 */
	public void devOnline(BusInstance busInstance) {
		
		if(!busInstance.isDevOnline()){
			busInstance.setLoginStatus(Constants.VAL_LOGIN_ONLINE);
		}
	}
	/**
	 * 设备离线（注销）
	 * @param devOnline
	 */
	public void devOffline(BusInstance busInstance) {
		
		if(busInstance.isDevOnline()){
			busInstance.setLoginStatus(Constants.VAL_LOGIN_OFFLINE);
		}
	}
	
	/**
	 * 加载车辆报警信息
	 * @param busInstance
	 */
	public void loadWarnProperties(BusInstance busInstance) {
		String plateNumber = busInstance.getBus().getBusPlateNumber();

		logger.debug("加载 {} 手动报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_6);
		logger.debug("加载 {} 偏线报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_7);
		logger.debug("加载 {} 超速报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_8);
		logger.debug("加载 {} 停车报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_9);
		logger.debug("加载 {} 回场报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_10);
		logger.debug("加载 {} 提前发车报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_11);
		logger.debug("加载 {} 延误发车报警数据", plateNumber);
		loadCurrentWarnMsg(busInstance, Constants.VAL_BUS_STATUS_12);

	}

	/**
	 * 加载车辆报警信息
	 * 
	 * @param busInstance
	 * @param warmType
	 */
	public void loadCurrentWarnMsg(BusInstance busInstance, String warmType) {
		// String devCode = busInstance.getDevice().getCode();
//		WarnMsg wm = warnMsgService.getWarnMsgByDev(busInstance.getBus().getBusDevUuid(), warmType);

//		if (wm != null) {
//			busInstance.setWarns(warmType, wm);
//			logger.debug("报警数据 {} ", wm.toString());
//		}
	}


}
